package com.evaluation.kexingcp.psycho.evaluation.sys.evaluation

import cn.hutool.core.date.DatePattern
import cn.hutool.core.date.DateUtil
import com.alibaba.fastjson.JSON
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper
import com.evaluation.kexingcp.admin.service.SysTenantService
import com.evaluation.kexingcp.common.core.util.R
import com.evaluation.kexingcp.common.data.tenant.TenantContextHolder
import com.evaluation.kexingcp.psycho.evaluation.sys.controller.vo.UserReportStatusVo
import com.evaluation.kexingcp.psycho.evaluation.sys.entity.EvaluationTaskEntity
import com.evaluation.kexingcp.psycho.evaluation.sys.entity.EvaluationTeamReportTemplatesEntity
import com.evaluation.kexingcp.psycho.evaluation.sys.service.EvaluationTaskService
import com.evaluation.kexingcp.psycho.evaluation.sys.service.EvaluationTaskUserRelService
import com.evaluation.kexingcp.psycho.evaluation.sys.service.EvaluationTeamReportTemplatesService
import jakarta.servlet.ServletRequest
import org.apache.poi.xwpf.usermodel.XWPFDocument
import org.springframework.core.io.InputStreamResource
import org.springframework.http.HttpHeaders
import org.springframework.http.MediaType
import org.springframework.http.ResponseEntity
import org.springframework.web.bind.annotation.*
import org.springframework.web.client.RestTemplate
import java.io.ByteArrayOutputStream
import java.net.URL
import java.util.zip.ZipEntry
import java.util.zip.ZipOutputStream


class TaskPublishRequest {
    var taskTime: String? = ""
    var taskName: String? = ""
    var taskDescribe: String? = ""
    var taskImportant: String? = ""
    var teamFeatureBg: String? = ""
    var taskLevel: Int? = null
    var scaleIds: List<String> = mutableListOf()

    var chartConfig: String? = ""
    var users: List<String> = mutableListOf()
    var canViewPersonalReport: Int? = 0
    var deptId: Long? = 0
    var isSendSms: Int = 0
}

data class UserTaskStatus(
    val userId: String?,
    val name: String?,
    val completed: Boolean?,
    val className: String?,
    val gradeName: String?,
    val completedTime: String?,
) {
    companion object {
        fun from(userReportStatusVo: UserReportStatusVo): UserTaskStatus {
            return UserTaskStatus(
                userReportStatusVo.userId.toString(),
                userReportStatusVo.name,
                userReportStatusVo.completed,
                userReportStatusVo.className,
                userReportStatusVo.gradeName,
                DateUtil.format(userReportStatusVo.completedTime, DatePattern.NORM_DATETIME_MINUTE_PATTERN)
            )
        }
    }
}

data class TaskCompleteStatus(
    val scaleName: String,
    val taskId: String,
    val taskName: String,
    val scaleId: String,
    val users: MutableList<UserTaskStatus>
)

@RestController
@RequestMapping("/evaluation/task")
open class EvaluationTaskScaleController(
    private val evaluationTaskScaleService: EvaluationTaskScaleService,
    private val evaluationTaskService: EvaluationTaskService,
    private val restTemplate: RestTemplate,
    private val sysTenantService: SysTenantService,
    private val evaluationTeamReportTemplatesService: EvaluationTeamReportTemplatesService,
    private val evaluationTaskUserRelService: EvaluationTaskUserRelService,
    private val evaluationNotifyService: EvaluationNotifyService
) {
    @PostMapping
    open fun evaluationScale(request: ServletRequest)
            : R<String> {
        val taskPublishRequest = JSON.parseObject<TaskPublishRequest>(
            request.inputStream.readBytes(),
            TaskPublishRequest::class.java
        )

        return evaluationTaskScaleService.publishTask(taskPublishRequest).fold(
            ifLeft = { err ->
                R.failed(err.message)
            },
            ifRight = {
                R.ok(it, "操作成功")
            }
        )
    }

    @GetMapping("/queryTaskData")
    open fun queryTaskData(): R<TaskData> {
        return evaluationTaskScaleService.queryTaskData().fold(
            ifLeft = { err ->
                R.failed(err.message)
            },
            ifRight = {
                R.ok(it, "操作成功")
            }
        )
    }

    @GetMapping("/queryTaskNum")
    open fun queryTaskNum(): R<TaskData> {
        return evaluationTaskScaleService.queryTaskNum().fold(
            ifLeft = { err ->
                R.failed(err.message)
            },
            ifRight = {
                R.ok(it, "操作成功")
            }
        )
    }

    @GetMapping("/queryScales")
    open fun queryScales(): R<List<EvaluationTaskEntity>> {
        return R.ok(evaluationTaskService.getTaskAndScales())
    }

    @GetMapping("/queryScales2")
    open fun queryScales2(): R<List<EvaluationTaskEntity>> {
        return R.ok(evaluationTaskService.getTaskAndScales2())
    }

    @GetMapping("/pdf/{tenantId}/{taskId}")
    open fun pdf(@PathVariable tenantId: Long, @PathVariable taskId: Long): R<String> {
        val tenant = sysTenantService.getById(TenantContextHolder.getTenantId())
        val templateUrl = if (tenant.teamReportTemplateId == null) {
            val template = evaluationTeamReportTemplatesService.getOne(
                QueryWrapper<EvaluationTeamReportTemplatesEntity>()
                    .eq("template_type", tenant.orgType)
                    .eq("template_is_default", 1)
            )

            template.templateUrl
        } else {
            val template = evaluationTeamReportTemplatesService.getOne(
                QueryWrapper<EvaluationTeamReportTemplatesEntity>()
                    .eq("id", tenant.teamReportTemplateId)
            )

            template.templateUrl
        }
        val task = evaluationTaskService.getById(taskId)
        val response = restTemplate.getForEntity(
            "http://182.92.80.67:8686?url=$templateUrl?params=$tenantId-$taskId",
            String::class.java
        )
        val url = response.body
        task.taskReportUrl = response.body
        evaluationTaskService.updateById(task)

        return R.ok(url)
    }

    // 下载个人报告ZIP文件流
    @GetMapping("/zip/{taskId}")
    fun downloadZip(@PathVariable taskId: Long): ResponseEntity<InputStreamResource> {
        val reports = evaluationTaskUserRelService.getTaskUserList(taskId)
        val baos = ByteArrayOutputStream()
        ZipOutputStream(baos).use { zos ->
            reports.forEach { report ->
                if (report.reportUrl == null) return@forEach
                val wordContent = getWordContent(report.reportUrl)
                val fileName = "${report.taskName}_${report.scaleName}_${report.name}.docx"

                zos.putNextEntry(ZipEntry(fileName))
                zos.write(wordContent)
                zos.closeEntry()
            }
        }

        val resource = InputStreamResource(baos.toByteArray().inputStream())
        return ResponseEntity.ok()
            .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=documents.zip")
            .contentType(MediaType.APPLICATION_OCTET_STREAM)
            .body(resource)
    }

    private fun getWordContent(url: String): ByteArray {
        val connection = URL(url).openConnection()
        connection.connect()
        connection.getInputStream().use { input ->
            XWPFDocument(input).use { document ->
                val baos = ByteArrayOutputStream()
                document.write(baos)
                return baos.toByteArray()
            }
        }
    }


    @GetMapping("/status/{taskId}")
    fun status(@PathVariable taskId: Long): R<MutableList<TaskCompleteStatus>> {
        val res = mutableListOf<TaskCompleteStatus>()
        evaluationTaskUserRelService.getUserCompleteStatus(taskId).groupingBy {
            it.scaleName
        }.aggregate { key, _: MutableList<TaskCompleteStatus>?, element, first ->
            if (first) {
                res.add(
                    TaskCompleteStatus(
                        key,
                        element.taskId.toString(),
                        element.taskName,
                        element.scaleId.toString(),
                        mutableListOf(UserTaskStatus.from(element))
                    )
                )
            } else {
                val status = res.find { it.scaleName == key }
                status?.users?.add(UserTaskStatus.from(element))
            }

            res
        }

        return R.ok(res)
    }

    data class MessageRequest(val title: String? = null, val userIds: List<String>? = null)

    @PostMapping("/message")
    fun getTaskUserList(@RequestBody request: MessageRequest): R<String> {
        evaluationNotifyService.sendSiteMessage(request.title!!, request.userIds?.map { it.toLong() }!!)
        return R.ok()
    }

    @GetMapping("/sum")
    fun getTaskSum(): R<Any> {
        return R.ok(evaluationTaskService.evaluationNumsByDate())
    }


}